package com.lcy.struct.memory;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

/**
 * @author lucongyang
 * @date Created in  16:43
 * @description 节点
 */
@Setter
@Getter
public class BPlusTree {
    /**
     * 当前节点的索引链
     */
    private List<BTreeIndex> indexList = new ArrayList<>();
    /**
     * 父节点
     */
    @JsonIgnore
    private BPlusTree parent;
    /**
     * 子节点
     */
    private List<BPlusTree> children;
    /**
     * 数据节点
     */
    private List<Object> dataList = null;
    /**
     * 父节点
     * 仅构树的时候用
     */
    @JsonIgnore
    private BPlusTree left;
    private List<BTreeIndex> leftIndex;
    private long leftPosition;
    /**
     * 父节点
     */
    @JsonIgnore
    private BPlusTree right;
    private List<BTreeIndex> rightIndex;
    private Long rightPosition;
    /**
     * 磁盘上的位置
     */
    private Long position;
    /**
     * 该节点呗分配的磁盘大小
     * 单位byte
     */
    private Long size;
    /**
     * 扩充磁盘的位置
     */
    private Long extendDiskPosition;

    /**
     * 分裂结果
     */
    public List<BPlusTree> splitResult() {
        List<BPlusTree> result = new ArrayList<>();
        int middleIndex = getMiddleIndex();

        BPlusTree left = new BPlusTree();
        BPlusTree middle = new BPlusTree();
        BPlusTree right = new BPlusTree();
        // 左子树
        List<BTreeIndex> leftIds = new ArrayList<>(this.indexList.subList(0, middleIndex));
        left.setIndexList(leftIds);
        // 中子树
        List<BTreeIndex> middleSingletonList = new ArrayList<>();
        middleSingletonList.add(this.indexList.get(middleIndex));
        middle.setIndexList(middleSingletonList);
        List<BPlusTree> middleChildren = new ArrayList<>();
        middleChildren.add(left);
        middleChildren.add(right);
        middle.setChildren(middleChildren);
        if (this.children == null || this.children.size() == 0) {
            // 如果是叶子节点
            // 右子树
            List<BTreeIndex> rightIds = new ArrayList<>(this.indexList.subList(middleIndex, this.indexList.size()));
            right.setIndexList(rightIds);
            // 加上数据节点
            left.setDataList(new ArrayList<>(this.dataList.subList(0, middleIndex)));
            right.setDataList(new ArrayList<>(this.dataList.subList(middleIndex, this.indexList.size())));
        } else {
            // 如果不是叶子节点
            List<BTreeIndex> rightIds = new ArrayList<>(this.indexList.subList(middleIndex + 1, this.indexList.size()));
            right.setIndexList(rightIds);
            int childMiddle = (int) (Math.ceil(this.children.size() / 2.));
            left.setChildren(new ArrayList<>(this.children.subList(0, childMiddle)));
            right.setChildren(new ArrayList<>(this.children.subList(childMiddle, this.children.size())));
        }
        // 执行完该方法后middle的子节点需要合并到新的节点的子节点中
        result.add(left);
        result.add(middle);
        result.add(right);
        return result;
    }

    public BPlusTree findChildren(int index) {
        return this.children.get(index);
    }

    @JsonIgnore
    public boolean isLeaf() {
        return this.children == null || this.children.size() == 0;
    }

    @JsonIgnore
    public boolean isRoot() {
        return this.parent == null;
    }

    public List<BTreeIndex> getParentId() {
        if (this.parent != null) {
            return this.parent.getIndexList();
        }
        return null;
    }

    private BTreeIndex findMiddle() {
        if (this.indexList == null || this.indexList.size() == 0) {
            return null;
        }
        if (this.indexList.size() < 2) {
            return indexList.get(0);
        }
        int middle = getMiddleIndex();
        return indexList.get(middle);
    }

    private Integer getMiddleIndex() {
        return indexList.size() / 2;
    }

    @Override
    public String toString() {
        String childrenIds = "";
        if (this.getChildren() != null && this.getChildren().size() > 0) {
            for (BPlusTree bPlusTree : this.children) {
                childrenIds += bPlusTree.indexList + ";";
            }
        }
        return this.getIndexList() + "\tchildren=" + childrenIds;
    }

    public void setDataList(List<Object> dataList) {
        this.dataList = dataList;
    }

    public void addData(int index, Object data) {
        if (this.dataList == null) {
            this.dataList = new ArrayList<>();
        }
        this.dataList.add(index, data);
    }
}
